"""

Trivia game for talkers and MU*s

TODO: 

 * Pickle scores in case connection is lost and game can restart gracefully

"""

import os
from time import sleep
import random
import sys
import cPickle
import unicodedata

from lyntin import exported
from lyntin.modules import modutils


#Number of credits to hand out
#XXX: Add command for host to set this.
AWARD = 25
#Sleep in seconds before output to talker
DELAY = .2
#Seconds between question and answer if nobody gets it right
Q_DELAY = 40
TRIVIA_DATA = "data/current.txt"


def showme(text):
    exported.lyntin_command("#showme %s" % text, internal=1, session=None)

def show_line(line, user=None):
    """Print one line with slight delay"""
    sleep(DELAY)
    #Send message only to user
    if user:
        exported.lyntin_command("#raw .writeuser %s %s" \
                % (user, line), internal=1, session=None)
    #Send message to bot's room
    else:
        if line:
            exported.lyntin_command("#raw .writeroom %s" \
                % line, internal=1, session=None)


class ManualGame(object):

    """Trivia game"""

    def __init__(self):
        self.question_asked = False
        self.question = ""
        self.answer = ""
        #self.trivia = []
        self.trivia = open(TRIVIA_DATA, "r").readlines()
        self.scores = {}
        self.nbr_games = 0
        #List of questions already asked so we don't do dupes
        self.asked = []
        #Any wizard or onyx can designate a regular user as a host.
        self.wizards = ["aine", "onyx", "honey", "lion", "mongo", "nicky",
                "officer", "raxas", "shar", "summer", "taria", "virus"]

        #Default hosts. Should be added when game starts with .trvnew
        self.hosts = ["aine"]
        #self.load_scores()


    def verify_level(self, host, wiz=None):
        """Verify user is allowed to control game"""
        if host == "wizard":
            return True
        if wiz and (host == "wizard" or host in self.wizards):
            return True
        if host not in self.hosts:
            #show_line('''Alex Trebot informs, "You haven't been authorized to host trivia."''', host)
            return False
        else:
            return True

    def remove_host(self, wiz, host):
        """Remove host from game"""
        if not self.verify_level(wiz, True):
            return
        if host in self.hosts:
            n = self.hosts.index(host)
            del self.hosts[n]
            show_line('Alex Trebot informs, "%s was removed as a trivia host."' % host)
        else:
            show_line('''Alex Trebot informs, "%s isn't a trivia host."''' % host, wiz)

    def add_host(self, admin, host):
        """Add new host"""
        if host == "who":
            show_line('Alex Trebot informs, "Current hosts: %s"' % 
                    ', '.join(map(str, self.hosts)))
            return
        if not self.verify_level(admin, True):
            return
        if host not in self.hosts:
            self.hosts.append(host)
            show_line('Alex Trebot informs, "%s was added as a trivia host."' % host)

    def save_scores(self):
        fh = open("scores.pkl","w")
        cPickle.dump(self.scores,fh)
        fh.close()

    def load_scores(self):
        try:
            fh = open("scores.pkl","r")
        except:
            self.scores = {}
            return
        self.scores = cPickle.load(self.scores, fh)
        fh.close()

    def adjust_score(self, host, player):
        if not self.verify_level(host):
            return
        if self.scores.has_key(player):
            self.scores[player] = self.scores[player] - 1
            showme("Score adjusted")
        sleep(DELAY)
        exported.lyntin_command(".steal %s %s" % (player, AWARD), internal=1,
                                session=None)

        sleep(DELAY)
        show_line("Score adjusted -1 for %s and %s credits deducted." % (player, AWARD))

    def score(self, host, player):
        #if not self.verify_level(host):
        #    return
        if self.scores.has_key(player):
            self.scores[player] = self.scores[player] + 1
        else:
            self.scores[player] = 1
        #sleep(DELAY)
        #exported.lyntin_command(".give %s %s" % (player, AWARD), internal=1, session=None)
        sleep(DELAY)
        show_line('AlexTrebot informs, "%s is the winner!"' % player.capitalize())

    def trivia_say_score(self, host):
        if not self.verify_level(host):
            return
        exported.lyntin_command(".writeroom ^tTrivia Scores: ^~" ,
                                internal=1,
                                session=None)

        for name in self.scores.keys():
            sleep(DELAY)

            score =  "%s" % self.scores[name]
            out = name.ljust(13) +  score.ljust(8)
            exported.lyntin_command(".writeroom ^t%s^~" % out,
                                internal=1,
                                session=None)


    def get_question(self):
        """Get random trivia question"""
        nbr_questions = len(self.trivia) - 1
        showme("%s" % nbr_questions)

        nbr = random.randint(0, nbr_questions)
        q_and_a = self.trivia[nbr]
        del self.trivia[nbr]
        outfile = open(TRIVIA_DATA, "w")
        outfile.writelines(self.trivia)
        outfile.close()

        part1, self.question = q_and_a.split("//")
        self.question = self.question.strip()
        #The command separator is ` so it needs to be replaced.
        #XXX: It may be possible to escape it with \
        self.question = self.question.replace('`', "'")
        parts = part1.split("/")
        category = parts[0]
        self.answer = []
        for ans in parts[2:]:
            ans = ans.strip()
            self.answer.append(ans)

    def say_answer(self, host):
        """Used to display answer and remove all scheduled events."""
        if not self.verify_level(host):
            return
        self.question_asked = False
        try:
            answer = self.answer[0].encode('ascii', 'ignore')
            exported.lyntin_command("#unschedule *", internal=1, session=None)
            exported.lyntin_command(".writeroom ^tAnswer: %s^~" % answer,
                                    internal=1,
                                    session=None)
        except:
            exported.lyntin_command(".writeroom The question had funny unicode characters, no comprendez!", internal=1, session=None)

    def award(self, host, winner):
        if not self.verify_level(host):
            return
        exported.lyntin_command(".give %s %s" % (winner, AWARD), internal=1, session=None)

    def deduct(self, host, loser):
        if not self.verify_level(host):
            return
        exported.lyntin_command(".steal %s %s" % (loser, AWARD), internal=1, session=None)

    def ask_question(self, host):
        if not self.verify_level(host):
            return
        if self.question_asked:
            show_line("^rA question has already been asked.^~", host)
            return

        self.get_question()
        self.question_asked = True
        exported.lyntin_command(".writeroom ^tNext question... (%s left)^~" % (len(self.trivia) + 1), internal=1, session=None)
        exported.lyntin_command("#schedule {5} {.writeroom ^t%s^~}" % 
                self.question, internal=1, session=None)
        
        for host in self.hosts:
            sleep(DELAY)
            if host != "wizard":
                exported.lyntin_command(".tell %s ANSWER: %s" % (host, self.answer[0]), internal=1, session=None)

            sleep(DELAY)
        
        exported.lyntin_command("#schedule {%s} {#trivia_answer {wizard}}" % Q_DELAY,
                                internal=1,
                                session=None)


MANUAL_GAME = ManualGame()

def cmd_question(ses, args, input):
    """Get random trivia question"""
    host = args["name"]
    MANUAL_GAME.ask_question(host)

def trivia_answer(ses, args, input):
    """Get random trivia question"""
    host = args["name"]
    MANUAL_GAME.say_answer(host)

def trivia_say_score(ses, args, input):
    """Get random trivia question"""
    host = args["name"]
    MANUAL_GAME.trivia_say_score(host)

def trivia_score(ses, args, input):
    """Add point for player"""
    host, target = args["name"].split(",")
    MANUAL_GAME.score(host, target)

def trivia_adjust_score(ses, args, input):
    """Get random trivia question"""
    host, target = args["name"].split(",")
    MANUAL_GAME.adjust_score(host, target)

def add_host(ses, args, input):
    """Add trivia host"""
    host, target = args["name"].split(",")
    MANUAL_GAME.add_host(host, target)

def remove_host(ses, args, input):
    """Remove trivia host"""
    host, target = args["name"].split(",")
    MANUAL_GAME.remove_host(host, target)

def trivia_award(ses, args, input):
    """Award player with bot's credits"""
    host, target = args["name"].split(",")
    MANUAL_GAME.award(host, target)

def trivia_deduct(ses, args, input):
    """Deduct credits from player for improperly awarded answer"""
    host, target = args["name"].split(",")
    MANUAL_GAME.deduct(host, target)

COMMANDS_DICT = {}
#Used for manual human-run games 
COMMANDS_DICT["trivia_single"] = (cmd_question, "name value= sortkey=")
COMMANDS_DICT["trivia_answer"] = (trivia_answer, "name value= sortkey=")
COMMANDS_DICT["trivia_award"] = (trivia_award, "name value= sortkey=")
COMMANDS_DICT["trivia_deduct"] = (trivia_deduct, "name value= sortkey=")
COMMANDS_DICT["trivia_score"] = (trivia_score, "name value= sortkey=")
COMMANDS_DICT["trivia_adjust_score"] = (trivia_adjust_score, "name value= sortkey=")
COMMANDS_DICT["trivia_say_score"] = (trivia_say_score, "name value= sortkey=")
COMMANDS_DICT["add_host"] = (add_host, "name value= sortkey=")
COMMANDS_DICT["remove_host"] = (remove_host, "name value= sortkey=")


def load():
    """ Initializes the module by binding all the commands."""
    modutils.load_commands(COMMANDS_DICT)

def unload():
    """ Unload things."""
    modutils.unload_commands(COMMANDS_DICT)

